package com.xiaoma.weblog.jwt.config.config;

import com.xiaoma.weblog.jwt.config.handler.RestAccessDeniedHandler;
import com.xiaoma.weblog.jwt.config.handler.RestAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @ClassName WebSecurityConfig
 * @Description: Spring Security 配置类
 * @Author: 小马
 * @CreateDate: 2025/3/27 14:46
 * @Version: 1.0
 *
 * 技术介绍
 *
 * 应用程序保护： 在当今互联网时代，应用程序安全性至关重要。Spring Security 提供了一系列的安全特性，帮助您保护应用程序免受恶意攻击，确保数据和功能不会被未经授权的用户访问。
 * 一站式解决方案： Spring Security 提供了一个集中的框架来处理各种安全性问题。从用户认证、授权到会话管理，Spring Security 提供了一个一站式的解决方案，使开发人员能够更容易地处理安全问题。
 * 多样的认证和授权方式： Spring Security 允许您以多种方式进行用户认证，包括基本认证、表单认证、OAuth 等。此外，您还可以定义精细的授权规则，确保只有经过授权的用户才能访问特定资源。
 * 与 Spring 集成： Spring Security 可与其他 Spring 项目无缝集成，如 Spring Boot、Spring MVC 等。这使得您可以轻松地将安全性集成到现有的 Spring 应用程序中。
 * 高度可定制： Spring Security 允许您根据应用程序的特定需求进行定制。您可以创建自定义的认证提供者、访问决策器、过滤器等，以适应不同的安全性要求。
 * 丰富的社区和文档： Spring Security 拥有活跃的社区和丰富的文档。您可以在社区中找到许多教程、示例代码和解决方案，以帮助您解决各种安全性问题。
 * 符合标准： Spring Security 符合各种安全性标准和最佳实践，确保您的应用程序满足行业和法规的要求。
 *
 * 什么是 HTTP Basic 认证？
 * HTTP Basic 认证是 Spring Security 中的一种认证方式，它基于 HTTP 基本认证协议。这种认证方式是一种简单的认证方式，适用于简单的应用场景。
 * 当客户端发送请求时，会将用户名和密码使用 Base64 编码的形式放在请求头中，服务器接收到请求后会解码并验证这些信息。
 *
 * 在 configure() 方法中，首先禁用了 CSRF（Cross-Site Request Forgery）攻击防护。在前后端分离的情况下，
 * 通常不需要启用 CSRF 防护。同时，还禁用了表单登录，并应用了 JWT 相关的配置类 JwtAuthenticationSecurityConfig。
 * 最后，配置会话管理这块，将会话策略设置为无状态（STATELESS），适用于前后端分离的情况，无需创建会话。
 *
 * @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)：这是一个 Spring Security 注解，用于启用方法级别的安全性设置。prePostEnabled = true
 * 表示启用 @PreAuthorize 和 @PostAuthorize 注解，securedEnabled = true 表示启用 @Secured 注解。这意味着您可以在方法级别使用这些注解来定义访问控制规则
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = false)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationSecurityConfig jwtAuthenticationSecurityConfig;
    @Autowired
    private RestAuthenticationEntryPoint authEntryPoint;
    @Autowired
    private RestAccessDeniedHandler deniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable(). // 禁用 csrf
                formLogin().disable() // 禁用表单登录
                .apply(jwtAuthenticationSecurityConfig) // 设置用户登录认证相关配置
                .and()
                .authorizeHttpRequests()
                .mvcMatchers("/admin/**").authenticated() // 认证所有以 /admin 为前缀的 URL 资源
                .anyRequest().permitAll() // 其他都需要放行，无需认证
                .and()
                .httpBasic().authenticationEntryPoint(authEntryPoint) // 处理用户未登录访问受保护的资源的情况
                .and()
                .exceptionHandling().accessDeniedHandler(deniedHandler) // 处理登录成功后访问受保护的资源，但是权限不够的情况
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 前后端分离，无需创建会话
                .and()
                .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 将 Token 校验过滤器添加到用户认证过滤器之前
        ;
    }

    /**
     * Token 校验过滤器
     * @return
     */
    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter() {
        return new TokenAuthenticationFilter();
    }
}